发送请求 - urllib.request
使用urllib.request模块,提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时还带有处理授权验证(authentication)、重定向(redirection)、浏览器Cookies 以及其他内容。
urlopen()
urlopen() 的基本使用
| 1 | import urllib.request | 
报错:urllib.error.URLError: 
解决:Python 坑之CERTIFICATE_VERIFY_FAILED
| 1 | import urllib.request | 
- class ‘http.client.HTTPResponse’- 是一个HTTPResponse类型的对象
- 包含read()、readinto()、getheader(name)、getheaders()、fileno()等方法
- 包含msg、version、status、reason、debuglevel、closed等属性
 
urlopen()函数的API
| 1 | urllib.request.urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, | 
- data - data=bytes(data),data接收的内容必须是bytes类型
- 一旦使用这个参数,请求方式变为POST - 1 
 2
 3
 4
 5
 6- import urllib.request 
 import urllib.parse
 data = bytes(urllib.parse.urlencode({'Hello':'World'}),encoding='utf-8')
 response = urllib.request.urlopen('http://httpbin.org/post',data=data)
 print(response.read())
 
- timeout - timeout参数用于设置超时时间,单位为秒,请求超过这个设置时间,还没有得到响应,就会抛出异常。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- import urllib.request 
 response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
 print(response.read())
 '''
 运行结果:
 urllib.error.URLError: <urlopen error timed out>
 错误原因超时
 设置为超时时间为0.1秒,0.1秒过后,程序无响应,于是抛出URLError异常
 URLError属于urllib.error模块,
 '''
- 设置超时时间来控制一个网页如果长时间未响应,就跳过它的抓取。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21- import urllib.request 
 import urllib.error
 import socket
 try:
 response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
 except urllib.error.URLError as e:
 if isinstance(e.reason, socket.timeout):
 print('TIME OUT')
 '''
 判断异常是不是socket.timeout类型,就是超时异常,从而确定它确实是因为超时而报错
 isinstance(object,classinfo):
 判断一个对象是否是一个已知的类型
 object == classinfo
 
 isinstance 和 type() 的区别:
 type()不能判断子类的实例化对象是不是属于父类
 
 推荐使用isinstance()
 '''
- context:必须是ssl.SSLContext类型,用来指定SSL设置 
- cafile:指定CA证书
- capth:指定CA证书的路径 - Request()- 使用urlopen()方法可以实现最基本的请求的发起,在之前的学习中, 就已经发现,它有一定的限制条件,并且可以从它的API接口中发现,参数也十分的简单,不足以构建一个完整的请求,那么Request类就能构建一个完整的需求。 - Request()的基本使用- 1 
 2
 3
 4
 5
 6
 7- import urllib.request 
 # 将请求独立成一个对象,这样可以丰富、灵活的配置参数
 request = urllib.request.Request('http://httpbin.org/get')
 # 依然使用urlopen来发送请求
 response = urllib.request.urlopen(request)
 print(response.read().decode('utf-8'))- Request()函数的API- 1 
 2
 3- urllib.request.Request(url, data=None, headers={}, 
 origin_req_host=None, unverifiable=False,
 method=None)
- url: - 请求url,必传参数,其他都是可选
 
- data:- 和urllib.request.urlopen()中一样,必须传bytes类型
- 如果传的类型是字典,可以先用urllib.parse.urlencode()编码
 
- headers:- 是字典类型,请求头
- 可以在构造请求时通过headers参数直接构造
- 另一种方式通过调用add_headers()方法添加,动态添加
 
- origin_req_host:- 请求方的host名称或者ip地址
 
- unverifiable:- 表示这个请求是否是无法验证的,默认为False,意思就是用户没有足够的权限来选择接受这个请求的结果
 
- method: - 用来指示请求使用的方法,比如GET、POST、PUT等
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41- from urllib import request,parse 
 # url
 url = 'http://httpbin.org/post'
 # 请求头
 headers = {
 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
 }
 # post请求数据
 data = {
 'name':'David'
 }
 # 传的类型是字典,所以要先用urllib.parse.urlencode()编码,指定编码格式为utf-8
 data = bytes(parse.urlencode(data),encoding='utf-8')
 # 构建POST请求
 request = request.Request(url=url,data=data,headers=headers,method='POST')
 response = request.urlopen(request)
 # bytes用utf-8解码
 print(response.read().decode('utf-8'))
 '''
 返回结果:
 {
 "args": {},
 "data": "",
 "files": {},
 "form": {
 "name": "David" # data传入的数据出现在form中,只有post请求才有
 },
 "headers": {
 "Accept-Encoding": "identity",
 "Content-Length": "10",
 "Content-Type": "application/x-www-form-urlencoded",
 "Host": "httpbin.org",
 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
 },
 "json": null,
 "origin": "61.171.88.179, 61.171.88.179",
 "url": "https://httpbin.org/post"
 }
 '''- Handler- Handler中有各种处理器,例如专门处理登陆验证,处理cookies的,处理代理设置等,利用这些我们可以做到HTTP请求中的所有事情。 - BaseHandler类- BaseHandler类是,所有其他Handler的父类,它提供了最基本的方法,例如:default_open()、protocol_request()等 
- HTTPDefaultErrorHandler: 用于处理http响应错误,错误抛出HTTPError类型的异常 
- HTTPRedirectHandler:用于处理重定向
- HTTPCookieProcessor:用于处理Cookies
- ProxyHandler:用于设置代理,默认代理为空
- HTTPPasswordMgr:用于管理密码,它维护用户名和密码表
- HTTPBasicAuthHandler:用于管理认证,当链接需要认证时,它可以解决认证问题 - OpenerDirector类- 通常称OpenerDirector为Opener,之前的urlopen()和Request就是urllib为我们封装了极其常用的请求方法,更多功能需要用到底层的实例来完成操作,所以要用到Opener。 - 验证- 请求网站时,弹出提示框,提示你需要输入用户名和密码,验证后才能查看页面 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22- from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener 
 from urllib.error import URLError
 username = 'username'
 password = 'password'
 url = 'http://0.0.0.0/#/Auth/get_basic_auth__user___passwd_'
 p = HTTPPasswordMgrWithDefaultRealm()
 # 利用add_password添加进去用户名和密码
 p.add_password(None,url,username,password)
 # 建立一个处理验证的Handler
 # 实例化HTTPBasicAuthHandler对象,其参数是HTTPPasswordMgrWithDefaultRealm对象
 auth_handler = HTTPBasicAuthHandler(p)
 # 利用Handler使用build_opener()方法构建一个Opener
 opener = build_opener(auth_handler)
 try:
 result = opener.open(url)
 html = result.read().decode('utf-8')
 print(html)
 except URLError as e:
 print(e.reason)- 代理- 爬虫免费代理 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- from urllib.request import ProxyHandler,build_opener 
 from urllib.error import URLError
 proxy_handler = ProxyHandler({
 'http':'http://0.0.0.0:9999',
 # 可以去西刺copy两个注意区分http和https,当然还有socks服务器
 'https':'https://0.0.0.0:9999'
 })
 opener = build_opener(proxy_handler)
 try:
 response = opener.open('http://www.baidu.com')
 print(response.read().decode('utf-8'))
 except URLError as e:
 print(e.reason)- 爬虫付费代理 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- # 方式一 
 import urllib.request
 #1.用户名密码和代理
 username = 'username'
 password = 'password'
 proxy = '127.0.0.1:8080'
 #2.创建密码管理器,添加用户名和密码
 password_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
 password_manager.add_password(None,proxy_money,use_name,pwd)
 #3.创建可以验证代理ip的处理器
 handle_auth_proxy = urllib.request.ProxyBasicAuthHandler(password_manager)
 #4.根据处理器创建opener
 opener_auth = urllib.request.build_opener(handle_auth_proxy)
 #5.发送请求
 response = opener_auth.open("http://www.baidu.com")
 print(response.read())- 1 
 2
 3
 4
 5
 6
 7
 8
 9- # 方式二 
 #1.代理ip
 money_proxy ={"http":"username:password@192.168.12.11:8080"}
 #2.代理的处理器
 proxy_handler=urllib.request.ProxyHandler(money_proxy)
 #3.通过处理器创建opener
 opener = urllib.request.build_opener(proxy_handler)
 #4.open发送请求
 opener.open("http://www.baidu.com")- Cookies- 获取网站cookies - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- import http.cookiejar 
 import urllib.request
 # 声明一个CookieJar对象
 cookies = http.cookiejar.CookieJar()
 # 利用HTTPCookieProcessor构建一个handler
 handler = urllib.request.HTTPCookieProcessor(cookies)
 # 构建opener
 opener = urllib.request.build_opener(handler)
 response = opener.open('http://www.baidu.com')
 print(type(cookies))
 for cookie in cookies:
 print(cookie.name + '=' + cookie.value)- 将cookies保存为文件 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- import urllib.request 
 import http.cookiejar
 # 保存cookies的文件名
 filename = 'cookies.txt'
 # 生成文件时,需要用到MozillaCookieJar 是 CookieJar的子类,处理和cookies和文件有关的事件
 cookie = http.cookiejar.MozillaCookieJar(filename)
 handler = urllib.request.HTTPCookieProcessor(cookie)
 opener = urllib.request.build_opener(handler)
 response = opener.open('http://www.baidu.com')
 cookie.save(ignore_discard=True, ignore_expires=True)- 从文件中读取cookies - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- import urllib.request 
 import http.cookiejar
 # 什么格式存的 就选什么格式
 cookie = http.cookiejar.MozillaCookieJar()
 # 用load()方法读取本地的cookies文件,获取cookies内容
 cookie.load('cookies.txt', ignore_expires=True, ignore_discard=True)
 handler = urllib.request.HTTPCookieProcessor(cookie)
 opener = urllib.request.build_opener(handler)
 response = opener.open('http://www.baidu.com')
 print(response.read().decode('utf-8'))